package cn.uc.ucgc.community.upgrade;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.PropertyConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.uc.ucgc.community.upgrade.api.ApiImplMgr;
import cn.uc.ucgc.community.upgrade.conf.ConfDealMgr;
import cn.uc.ucgc.community.upgrade.shell.ShellMgr;

/**
 * 升级框架执行入口
 * 
 * @author yuyj@ucweb.com
 * @createDate 2014-1-2
 *
 */
public class Main {
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    private static final String UPGRADE_LOG4J_PATH_KEY = "upgrade.log4j.path";
    private static boolean bColMacroKeys = false;

    public static void main(String[] args) {

        //加载log4j配置文件
        String log4jLogPath = System.getProperty("upgrade.log4j.path");
        if (null == log4jLogPath || log4jLogPath.isEmpty()) {
            System.setProperty(UPGRADE_LOG4J_PATH_KEY, "var/logs");
        }
        URL log4jCfg = Main.class.getClassLoader().getResource(
                "cn/uc/ucgc/community/upgrade/log4j.properties");
        PropertyConfigurator.configure(log4jCfg);

        //1)对输入参数的校验；
        if (null == args || args.length < 1) {
            printHeloInfo();
            return;
        }

        if (false == resolveArgs(args)) {
            return;
        }

        logger.info("appOldPath:\t" + AppArgs.appOldPath + "\n" + "appNewPath:\t"
                + AppArgs.appNewPath + "\n" + "confPath:\t" + AppArgs.confPath + "\n");

        if (false == allFileExists()) {
            return;
        }

        //2)解析任务列表，获取的待完成的任务
        try {
            //仅仅是收集宏配置(便于研发使用)
            if (bColMacroKeys) {
                ConfDealMgr.getInstance().initTask(true);
                return;
            }

            logger.warn(Constants.TASK_SPLIT);
            //配置文件
            ConfDealMgr.getInstance().initTask(false);
            //API扩展
            ApiImplMgr.getInstance().initTask();
            //shell脚本
            ShellMgr.getInstance().initTask();
        } catch (Exception e) {
            logger.error("Init Task Error", e);
            return;
        }
        List<Task> needDoTask = new ArrayList<Task>();
        //3)依次按约定顺序执行任务
        try {
            //3.1)首先执行全局的配置任务
            addTask(needDoTask, ConfDealMgr.getInstance().getFullReplaceTask());
            addTask(needDoTask, ConfDealMgr.getInstance().getReplaceTask());
            addTask(needDoTask, ConfDealMgr.getInstance().getModifyTask());
            addTask(needDoTask, ConfDealMgr.getInstance().getDeleteTask());
            addTask(needDoTask, ConfDealMgr.getInstance().getAddTask());
            //3.2)依次执行预处理任务
            addTask(needDoTask, ApiImplMgr.getInstance().getPrepareTask());
            addTask(needDoTask, ShellMgr.getInstance().getPrepareTask());
            //3.3)依次执行任务
            addTask(needDoTask, ApiImplMgr.getInstance().getExeTask());
            addTask(needDoTask, ShellMgr.getInstance().getExeTask());
            //3.4)依次执行修正任务
            addTask(needDoTask, ApiImplMgr.getInstance().getReviseTask());
            addTask(needDoTask, ShellMgr.getInstance().getReviseTask());
            //依次执行任务，如果有异常立即中断
            for (Task task : needDoTask) {
                task.run();
                if (task.isFinish()) {
                    continue;
                }
                //说明任务未完成，终止后续任务，并做回滚处理
                logger.error("upgrade task will be ending");
                break;
            }

        } catch (Exception e) {
            //说明发生了异常，记录日志
            logger.error("", e);
        }
        //4)汇总显示任务执行情况
        StringBuilder sb = new StringBuilder();
        sb.append(Constants.TASK_SPLIT).append(Constants.LINE_SEPARATOR);
        int totalSize = needDoTask.size();
        int finish = 0;
        sb.append("\t Total Task: ").append(totalSize).append(Constants.LINE_SEPARATOR);
        for (Task task : needDoTask) {
            if (!task.isFinish()) {
                break;
            }
            finish++;
        }
        sb.append("\t Finish Task: ").append(finish).append(Constants.LINE_SEPARATOR);
        sb.append("\t Failed Task: ").append((totalSize - finish)).append(Constants.LINE_SEPARATOR);
        sb.append(Constants.TASK_SPLIT);
        logger.info(sb.toString());
    }

    private static void addTask(List<Task> needDoTask, Task task) {
        if (null != task) {
            needDoTask.add(task);
        }
    }

    private static void printHeloInfo() {
        logger.error(Constants.TOOL_OPTION_ERROR_TIP);
    }

    private static boolean resolveArgs(String[] args) {

        if (args.length == 1 && args[0].equals(Constants.TOOL_HELP_OPTION)) {
            logger.info(Constants.TOOL_HELP_TIP);
            return false;
        }

        if (args.length > 7) {
            logger.error(Constants.TOOL_OPTION_ENTER_ERROR_TIP);
            return false;
        }
        int argsLen = args.length;
        int loopLen = argsLen;
        if (argsLen % 2 == 1) {
            loopLen = argsLen - 1;
            if (args[argsLen - 1].equals(Constants.TOOL_MACRO_CMD)) {
                bColMacroKeys = true;
            } else {
                //参数非法
                logger.error(Constants.TOOL_OPTION_ENTER_ERROR_TIP);
                return false;
            }
        }

        for (int i = 0; i < loopLen; i = i + 2) {
            if (null == args[i]) {
                logger.error(Constants.TOOL_OPTION_ENTER_ERROR_TIP);
                return false;
            }
            if (args[i].equals(Constants.TOOL_APP_OLD_PATH_OPTION)) {

                if (AppArgs.appOldPath.isEmpty()) {
                    AppArgs.appOldPath = args[i + 1];
                } else {
                    //如果appOldPath不为空，说明已经赋过值，也就是同样的参数多次输入了。
                    logger.error(Constants.TOOL_OPTION_ENTER_ERROR_TIP);
                    return false;
                }

            } else if (args[i].equals(Constants.TOOL_APP_NEW_PATH_OPTION)) {

                if (AppArgs.appNewPath.isEmpty()) {
                    AppArgs.appNewPath = args[i + 1];
                } else {
                    //如果appNewPath不为空，说明已经赋过值，也就是同样的参数多次输入了。
                    logger.error(Constants.TOOL_OPTION_ENTER_ERROR_TIP);
                    return false;
                }

            } else if (args[i].equals(Constants.TOOL_CONF_PATH_OPTION)) {

                if (AppArgs.confPath.isEmpty()) {
                    AppArgs.confPath = args[i + 1];
                } else {
                    //如果confPath不为空，说明已经赋过值，也就是同样的参数多次输入了。
                    logger.error(Constants.TOOL_OPTION_ENTER_ERROR_TIP);
                    return false;
                }
            } else {
                logger.error(Constants.TOOL_OPTION_ENTER_ERROR_TIP);
                return false;
            }
        }

        //前面的逻辑已经能确保AppArgs里所有属性不会为null，故以下无需验证是否为null
        if (AppArgs.appOldPath.isEmpty() || AppArgs.appNewPath.isEmpty()) {
            logger.error(Constants.TOOL_OPTION_ERROR_TIP);
            return false;
        }
        return true;
    }

    /**
     * 验证程序运行所需文件目录是否存在。
     * @return
     */
    public static boolean allFileExists() {
        //验证老应用主目录和新路径主目录是否存在
        AppFiles.oldVerHomeFile = new File(AppArgs.appOldPath);
        if (!AppFiles.oldVerHomeFile.exists()) {
            logger.error("{} must be exist!", AppArgs.appOldPath);
            return false;
        }

        AppFiles.newVerHomeFile = new File(AppArgs.appNewPath);
        if (!AppFiles.newVerHomeFile.exists()) {
            logger.error("{} must be exist!", AppArgs.appNewPath);
            return false;
        }

        if (!AppArgs.confPath.isEmpty()) {
            AppFiles.confHomeFile = new File(AppArgs.confPath);
            if (!AppFiles.confHomeFile.exists()) {
                logger.error("{} must be exist!", AppArgs.confPath);
                return false;
            }
        }
        return true;
    }
}
